\chapter{Plugins}
\label{chap:plugins}

Gantry is extensible in many ways.  Most of the time it is enough to just
use standard and CPAN modules in the regular way.  But there are times when
a bit more is required.  This chapter explains how we
implement plugins which change -- or more likely, augment -- the behavior
of Gantry site objects.

Most plugins alter the behavior of Gantry site objects by mixing in
methods.  This is easy to do.
To have an example, suppose that a database we don't control gives us
data in feet, but we need to show it to our customer in meters.  To make
it easy to access this method in controller methods, we want the syntax
to be like this:
{\footnotesize
\begin{verbatim}
    my $meters = $self->ft2m( $feet_from_database );
\end{verbatim}
}
\noindent
But, we only want \verb+ft2m+ to be available, we don't want it by default.
That rules out putting it into Gantry.pm.  Further, while we could put it in
our app's main module, that wouldn't help us if a different app needs the
same conversion.  So, let's make a plugin\index{plugin}:

{\footnotesize
\begin{verbatim}
package Gantry::Plugins::UnitConvert
use strict;

use Exporter;
our @EXPORT = qw( ft2m );

sub ft2m {
    my $self = shift;
    my $feet = shift;

    return $feet * .3048;
}
\end{verbatim}
}

The key is to write a method (which expects a Gantry site object as its
invocant) and export it -- or mix it -- into the caller's namespace.
Users then have an array of choices for how to use this plugin.
They could include it in the same
use statement\index{use!plugin}\index{Gantry!full use statement}
where they choose an Engine:

{\footnotesize
\begin{verbatim}
    use GantryBased::App qw(
            -Engine=MP13 -TemplateEngine=TT UnitConvert
    );
\end{verbatim}
}

But that puts it in all the modules of the whole app.  Likely, it will make
more sense to use it more sparingly, in the modules which actually need it.
So, it should probably go near the top of the module that needs it:

{\footnotesize
\begin{verbatim}
package GantryBased::App::Dist
use strict;
#...
use Gantry::Plugins::UnitConvert qw( ft2m );
\end{verbatim}
}

Note that the user does not have to import the \verb+ft2m+ method by name,
but it will help future readers who wonder where that method came from.
You could also choose to have your plugin export only upon request, by
changing from
\verb+@EXPORT+\index{EXPORT}
to
\verb+@EXPORT_OK+.
That seems a bit
strange for most plugins, since their whole purpose in life is to inject
their methods into your namespace, but some people may prefer it.  It does
force users to ask for the methods.  That's good documentation.  It also
makes more sense if there are more methods in the plugin, only some
of which make sense together.

Gantry's plugins are generally mixins -- they export methods into their
user's namespace.  This is a powerful way to share code across apps without
worrying about inheritance.  If you stick to explicit imports, it is still
fairly easy to track down the origin of the code.

The only plugin that doesn't export is Gantry::Plugins::CRUD which has
an object oriented approach.  It is in the Plugins namespace due to its
similarity with Gantry::Plugins::AutoCRUD, which does export a number of
methods.

\section{Gantry's handler
phases\index{Gantry!handler phases}\index{callbacks!from Gantry handler}
}

Some plugins need to operate autonomously during each request.  For example,
Gantry::Plugins::AuthCookie needs to validate user login credentials
before the handler calls any \verb+do_*+ method.  Gantry provides a simple
registration scheme for this purpose.

\begin{table}
\begin{center}
\begin{tabular}{l|l}
Name & Timing \\
\hline
\verb+pre_init+      & immediately before calling init              \\
\verb+init+          & at the start of init                         \\
\verb+post_init+     & immediately after init returns               \\
\verb+pre_process+   & immediately before calling \verb+do_process+ \\
\verb+post_process+  & immediately after \verb+do_process+ returns  \\
\end{tabular}
\end{center}
\caption{Gantry's handler phases that can call you back.}
\label{tab:handlerphases}
\end{table}

There are five spots during Gantry's handler where your callbacks can
be called (aside from the normal action spot which invokes a \verb+do_*+
method).
These are shown in Table \ref{tab:handlerphases}.

The \verb+pre_init+ callback happens after the site object is blessed,
but before anything is put in it.  All callbacks are invoked through
the site object, this one also receives the request object or CGI object
as a parameter.  This is a good place to steal the body of a POST
request before your engine can try to turn it into form parameters.
The SOAP plugin does this.

The \verb+init+ callback happens after the engine init and these
have been set: \verb+uri+, \verb+location+, \verb+path_info+, and
\verb+method+.

If you want to be called at one or more of those times, provide
a method called \verb+get_callbacks+.  Gantry will call this whenever someone
uses your plugin in their full use statement, as in this example:

{\footnotesize
\begin{verbatim}
use Some::Application qw(
        -PluginNamespace=some_string YourPlugin
);
\end{verbatim}
}

The \verb+-PluginNamespace+ must match the return value of the
\verb+namespace+ method,
for the callbacks to execute.  This allows individual controllers 
to accept or reject the callbacks, by overriding \verb+namespace+.
Note that while \verb+-PluginNamespace+ could be included in the same
use as \verb+-Engine+, it doesn't need to be.  You can put it in any
use statement for any Gantry descended controller.

Namespace use is optional (though it may cost you a warning).  Using it
allows Gantry to register the callbacks only for the apps, and controllers,
that want them.  Failure to use namespaces forces the callbacks on all
apps in the Apache instance.

\verb+get_callbacks+\index{get
callbacks@\verb+get_callbacks+}\index{callback
registration}\index{Gantry!callback registration}
is a class method, which is given only the namespace.
You should not re-register the same callbacks for the same namespace.  Doing
so will likely result in duplicate calls to the callbacks.  Return a
list of callback hashes.  Here is \verb+get_callbacks+ from the AuthCookie
plugin\footnote{note that you must return a list of hash references}:

{\footnotesize
\begin{verbatim}
my %registered_callbacks;

sub get_callbacks {
    my ( $class, $namespace ) = @_;

    return if ( $registered_callbacks{ $namespace }++ );

    warn 'Use -PluginNamespace=something when you use '
            .   'Gantry::Plugins::AuthCookie'
         if ( $namespace eq 'Gantry' );

    return (
        { phase => 'init',      callback => \&initialize },
        { phase => 'post_init', callback => \&auth_check },
    );
}
\end{verbatim}
}

This example registers the
\verb+initialize+\index{initialize!AuthCookie callback registration}
method to be called at the start of \verb+init+.  This ensures that \verb+uri+,
\verb+location+, \verb+path_info+, and \verb+method+ will
be available.  By running at the start of \verb+init+, instead of after
it, the plugin allows app level \verb+init+ methods to programmatically
override the values of the conf variables it sets.

The
\verb+auth_check+\index{auth check@\verb+auth_check+!AuthCookie
callback registration}
method is called immediately after the controller's \verb+init+ method
finishes,\begin{footnote}
Note that \verb+init+ methods are frequently inherited.
\end{footnote}
during the \verb+post_init+
phase.  It can then deny access to the page before the \verb+do_+
method has a chance to run.

\section*{Summary}

So, Gantry plugins are really mixins which may choose to register callbacks
to be called during Gantry's handler processing.
